package com.swotxu.oldwebproject.redis.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.SerializationException;
import org.apache.log4j.Logger;

import java.nio.charset.Charset;

/**
 * FastJson 序列化
 * 序列化：
 * 1、将目标数据统一包装为 RedisSerializer.RedisJsonWraper 对象
 * 2、对包装对象 RedisSerializer.RedisJsonWraper 进行序列化为二进制数组返回
 * 反序列化：
 * 1、将二进制数组反序列化为 RedisSerializer.RedisJsonWraper 包装对象
 * 2、从包装对象 RedisSerializer.RedisJsonWraper 中获取目标数据返回
 *
 * fastJson部分问题：
 * 1、autoType问题
 * 在高版本中，autoType默认为false，即：无法将json字符串转为自定义实体对象。
 * 解决方式：
 * a、定义白名单。如：arserConfig.getGlobalInstance().addAccept("com.sse.modules.mainpage.pojo.CompanyInbox");
 * b、开启aotoType。注：不建议修改全局配置。可定义局部配置，设置为true。
 * ParserConfig parserConfig = new ParserConfig();
 * parserConfig.setAutoTypeSupport(true);
 *
 * 2、实体对象属性丢失问题
 * 实体对象属性，必须提供对应的 getter and setter方法，否则属性数据无法序列化。
 * 如：UserInfo对象中，m属性无 getter and setter方法，序列化后数据丢失。
 *
 * @Date: 2020/2/20 10:04
 * @Author: xu.hai
 */
public class FastJsonRedisSerializer {
    private static final Logger logger = Logger.getLogger(FastJsonRedisSerializer.class);
    /** 自定义局部 FastJson配置 */
    private static final ParserConfig parserConfig = new ParserConfig();
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    static {
        // ParserConfig.getGlobalInstance().addAccept("com.sse.modules.mainpage.pojo.CompanyInbox");
        // ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        // 开启局部配置文件的 autoType -- 不修改全局配置信息，减少FastJson安全漏洞风险
        parserConfig.setAutoTypeSupport(true);
    }

    /**
     * 序列化
     * @param t
     * @param <T>
     * @return
     * @throws SerializationException
     */
    public static <T> byte[] serialize(T t) throws SerializationException {
        if(t == null){
            return new byte[0];
        }
        RedisSerializer.RedisJsonWraper<T> wraper = new RedisSerializer.RedisJsonWraper(t);
        return JSON.toJSONString(wraper, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    /**
     * 反序列化
     * @param bytes
     * @param <T>
     * @return
     * @throws SerializationException
     */
    public static <T> T deserialize(byte[] bytes) throws SerializationException {
        if (ArrayUtils.isEmpty(bytes)) {
            return null;
        }
        String deserializeStr = new String(bytes, DEFAULT_CHARSET);
        logger.debug(deserializeStr);
        RedisSerializer.RedisJsonWraper<T> wraper = JSON.parseObject(deserializeStr, RedisSerializer.RedisJsonWraper.class, parserConfig);
        return wraper.getValue();
    }
}
